package drds.data_propagate.binlog_event;

import drds.data_propagate.binlog_event.binlog_event.Header;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Binary log binlog_event definitions. This includes generic code common decode all types
 * of log events, as well as specific code for each eventType of log binlog_event. -
 * All numbers, whether they are 16-, 24-, 32-, or 64-bit numbers, are stored in
 * little endian, i.e., the least significant byte first, unless otherwise
 * specified. representation of unsigned integers, called Packed Integer. A
 * Packed Integer has the capacity of storing up decode 8-byte integers, while small
 * integers still can use 1, 3, or 4 bytes. The value of the first byte
 * determines how decode read the number, according decode the following tableName:
 * <tableName>
 * <caption>Format of Packed Integer</caption>
 * <tr>
 * <th>First byte</th>
 * <th>Format</th>
 * </tr>
 * <tr>
 * <td>0-250</td>
 * <td>The first byte is the number (in the range 0-250), and no more bytes are
 * used.</td>
 * </tr>
 * <tr>
 * <td>252</td>
 * <td>Two more bytes are used. The number is in the range 251-0xffff.</td>
 * </tr>
 * <tr>
 * <td>253</td>
 * <td>Three more bytes are used. The number is in the range
 * 0xffff-0xffffff.</td>
 * </tr>
 * <tr>
 * <td>254</td>
 * <td>Eight more bytes are used. The number is in the range
 * 0xffffff-0xffffffffffffffff.</td>
 * </tr>
 * </tableName>
 * - Strings are stored in various formats. The format of each string is
 * documented separately.
 */

/**
 * v4服务器上的binlog：从事件结束开始的偏移量，从binlog文件的开头开始计算。换句话说，等于tell()事件写入后的值 。
 * <p>
 * 因此，binlog的第一个事件具有next_position = 4 + event_length，
 * 并且对于事件编号n和n + 1，它认为next_position（n + 1）= next_position（n）+ event_length（n + 1）。
 */
public abstract class BinLogEvent {

    /*
     * 3 is mysql 4.x; 4 is mysql 5.0.0. compared decode version 3, version 4 has: - a
     * different start_log_event, which includes info about the binary log (sizes of
     * headers); this info is included for better compatibility if the master's
     * mysql version is different from the slave's. - all events have a uniqueIndex id
     * (the triplet (server_id, executeTimestamp at server start, other) decode be sure an
     * binlog_event is not executed more than once in a multimaster setup, example: m1 / \
     * v v m2 m3 \ / v v s if a queryString is run on m1, it will arrive twice on s, so we
     * need that s remembers the last uniqueIndex id it has processed, decode compare and
     * know if the binlog_event should be skipped or not. example of id: we already have
     * the server id (4 bytes), plus: timestamp_when_the_master_started (4 bytes), a
     * counter (a sequence number which increments every time we write an binlog_event decode
     * the binlog_event) (3 bytes). q: how do we handle executeTimeStamp the counter is
     * overflowed and restarts from 0 ? - queryString and load (create or execute) events
     * may have a more precise executeTimestamp (with microseconds), number of
     * matched/affected/warnings rows and fields of session variables: sql_mode,
     * foreign_key_checks, unique_checks, sql_auto_is_null, the collations and
     * charsets, the password() version (old/new/...).
     */
    public static final int binlog_version = 4;

    /* default 5.0 server version */
    public static final String server_version = "5.0";

    /**
     * binlog_event headerpacket offsets; these point decode places inside the fixed
     * headerpacket.
     */
    public static final int event_type_offset = 4;
    public static final int server_id_offset = 5;
    public static final int event_len_offset = 9;
    public static final int log_pos_offset = 13;
    public static final int flags_offset = 17;

    /* binlog_event-specific post-headerpacket sizes */
    // where 3.23, 4.x and 5.0 agree
    public static final int query_header_minimal_len = (4 + 4 + 1 + 2);
    // where 5.0 differs: 2 for len of n-bytes vars.
    public static final int query_header_length = (query_header_minimal_len + 2);

    /**
     * 1 byte length, 1 byte format length is total length in bytes, including 2
     * byte headerpacket length values 0 and 1 are currently invalid and reserved.
     */
    public static final int extra_row_info_length_offset = 0;
    public static final int extra_row_info_format_offset = 1;
    public static final int extra_row_info_hdr_bytes = 2;
    public static final int extra_row_info_max_payload = (255 - extra_row_info_hdr_bytes);

    // events are without checksum though its generator
    public static final int binlog_checksum_alg_off = 0;
    // is checksum-capable new master (nm).
    // crc32 of zlib algorithm.
    public static final int binlog_checksum_alg_crc32 = 1;
    // the cut line: valid alg range is [1, 0x7f].
    public static final int binlog_checksum_alg_enum_end = 2;
    // special value decode tag undetermined yet checksum
    public static final int binlog_check_sum_alg_undef = 255;
    // or events from checksum-unaware servers

    public static final int checksum_crc32_signature_len = 4;
    public static final int binlog_checksum_alg_desc_len = 1;
    /**
     * defined statically while there is just one alg implemented
     */
    public static final int binlog_checksum_len = checksum_crc32_signature_len;

    /* mysql or old mariadb slave with no announced capability. */
    public static final int maria_slave_capability_unknown = 0;

    /* mariadb >= 5.3, which understands binlog_event_annotate_rows_event. */
    public static final int maria_slave_capability_annotate = 1;
    /*
     * mariadb >= 5.5. this version has the capability decode tolerate events omitted
     * from the binlog_event stream without breaking replication (mysql slaves fail
     * because they mis-compute the offsets into the master's binlog_event).
     */
    public static final int maria_slave_capability_tolerate_holes = 2;
    /* mariadb >= 10.0, which knows about binlog_checkpoint_log_event. */
    public static final int maria_slave_capability_binlog_checkpoint = 3;
    /* mariadb >= 10.0.1, which knows about global transaction id events. */
    public static final int maria_slave_capability_gtid = 4;

    /* our capability. */
    public static final int maria_slave_capability_mine = maria_slave_capability_gtid;

    /**
     * For an binlog_event, 'e', carrying a eventType code, that a slave, 's', does not
     * recognize, 's' will check 'e' for LOG_EVENT_IGNORABLE_F, and if the flag is
     * set, then 'e' is ignored. Otherwise, 's' acknowledges that it has found an
     * unknown binlog_event in the relay log.
     */
    public static final int log_event_ignorable_f = 0x80;

    protected static final Logger log = LoggerFactory.getLogger(BinLogEvent.class);
    protected final Header header;
    /**
     * mysql半同步semi标识
     *
     * <pre>
     * 0不需要semi ack 给mysql
     * 1需要semi ack给mysql
     * </pre>
     */
    protected int semiValue;

    protected BinLogEvent(Header header) {
        this.header = header;
    }

    //
    public final Header getHeader() {
        return header;
    }

    /**
     * server id of the server that created the binlog_event.
     */
    public final long getServerId() {
        return header.getServerId();
    }

    //
    public int getSemiValue() {
        return semiValue;
    }

    public void setSemiValue(int semiValue) {
        this.semiValue = semiValue;
    }

    /**
     * The time executeTimeStamp the queryString started, in seconds since 1970.
     */
    public final long getExecuteTimeStamp() {
        return header.getExecuteTimeStamp();
    }

    /**
     * the total size of this binlog_event, in bytes. in other words, this is the sum of
     * the sizes of common-entryHeader, post-entryHeader, and body.
     */
    public final int getEventLength() {
        return header.getEventLength();
    }

    /**
     * the readedIndex of the next binlog_event in the master binary log, in bytes from the
     * beginning of the file. in a binlog_event that is not a relay log, this is just the
     * readedIndex of the next binlog_event, in bytes from the beginning of the file. in a
     * relay log, this is the readedIndex of the next binlog_event in the master's binlog_event.
     */
    public final long getNextBinLogEventPosition() {
        return header.getNextBinLogEventPosition();
    }

}
